﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;

namespace MyLinqHelper
{
    public abstract class LinQDAO<TEntity, TDataContext> 
        where TEntity : class, new()
        where TDataContext : DataContext, new()
    {
        private DataContext context;
        private Table<TEntity> entityTable;
     
        public LinQDAO()
        {
            this.context = Activator.CreateInstance<TDataContext>();
            this.entityTable = context.GetTable<TEntity>();
        }

        public void CreateItem(TEntity item)
        {
            try
            {
                this.entityTable.InsertOnSubmit(item);
                this.context.SubmitChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void DeleteItem(object id)
        {
            try
            {
                TEntity item = this.GetById(id);
                this.entityTable.DeleteOnSubmit(item);
                this.context.SubmitChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void UpdateItem(TEntity item)
        {
            try
            {
                this.context.SubmitChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<TEntity> GetAll()
        {
            return this.entityTable.ToList<TEntity>();
        }

        public TEntity GetById(object id)
        {
            try
            {
                Criteria c = new Criteria();
                c.Add(new Criterion(Comparision.Equal, this.GetIdName(), id));
                return GetItem(c);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public TEntity GetItem(Criteria c)
        {
            try
            {
                IQueryable<TEntity> queryableData = this.entityTable.AsQueryable<TEntity>();
                IQueryable<TEntity> results = queryableData.Provider.CreateQuery<TEntity>(c.GetExpression<TEntity>(queryableData));
                return results.SingleOrDefault<TEntity>();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<TEntity> GetItems(Criteria c)
        {
            try
            {
                IQueryable<TEntity> queryableData = this.entityTable.AsQueryable<TEntity>();
                IQueryable<TEntity> results = queryableData.Provider.CreateQuery<TEntity>(c.GetExpression<TEntity>(queryableData));
                return results.ToList<TEntity>();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<TEntity> GetItems(string orderBy, string orderDirection)
        {
            try
            {
                IQueryable<TEntity> queryableData = this.entityTable.AsQueryable<TEntity>();
                return queryableData.OrderBy<TEntity>(string.Format("{0} {1}", orderBy, orderDirection)).ToList<TEntity>();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<TEntity> GetItems(string orderBy, string orderDirection, int page, int pageSize, out int totalRecords)
        {
            try
            {
                IQueryable<TEntity> queryableData = this.entityTable.AsQueryable<TEntity>();
                totalRecords = queryableData.Count();
                return queryableData.OrderBy<TEntity>(string.Format("{0} {1}", orderBy, orderDirection)).Skip<TEntity>(page).Take<TEntity>(pageSize).ToList<TEntity>();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<TEntity> GetItems(Criteria c, string orderBy, string orderDirection)
        {
            try
            {
                IQueryable<TEntity> queryableData = this.entityTable.AsQueryable<TEntity>();
                IQueryable<TEntity> results = queryableData.Provider.CreateQuery<TEntity>(c.GetExpression<TEntity>(queryableData));
                return results.OrderBy<TEntity>(string.Format("{0} {1}", orderBy, orderDirection)).ToList<TEntity>();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<TEntity> GetItems(Criteria c, string orderBy, string orderDirection, int page, int pageSize, out int totalRecords)
        {
            try
            {
                IQueryable<TEntity> queryableData = this.entityTable.AsQueryable<TEntity>();
                IQueryable<TEntity> results = queryableData.Provider.CreateQuery<TEntity>(c.GetExpression<TEntity>(queryableData));
                totalRecords = results.Count();
                return results.OrderBy<TEntity>(string.Format("{0} {1}", orderBy, orderDirection)).Skip<TEntity>(page).Take<TEntity>(pageSize).ToList<TEntity>();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public abstract string GetIdName();
    }
}
